package org.eiahe.hr.attendance.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.ehe.common.core.utils.MapstructUtils;
import org.ehe.common.mybatis.core.page.PageQuery;
import org.ehe.common.mybatis.core.page.TableDataInfo;
import org.eiahe.hr.attendance.domain.*;
import org.eiahe.hr.attendance.domain.bo.AttendanceAlertBo;
import org.eiahe.hr.attendance.domain.vo.AttendanceAlertVo;
import org.eiahe.hr.attendance.mapper.AttendanceAlertMapper;
import org.eiahe.hr.attendance.mapper.AttendanceRecordMapper;
import org.eiahe.hr.attendance.mapper.OvertimeRecordMapper;
import org.eiahe.hr.attendance.service.IAttendanceAlertService;
import org.ehe.system.domain.HrEmployee;
import org.ehe.system.mapper.HrEmployeeMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 考勤异常提醒Service业务层处理
 *
 * @author zhangnn
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class AttendanceAlertServiceImpl implements IAttendanceAlertService {

    private final AttendanceAlertMapper baseMapper;
    private final AttendanceRecordMapper attendanceRecordMapper;
    private final OvertimeRecordMapper overtimeRecordMapper;
    private final HrEmployeeMapper employeeMapper;

    @Override
    public TableDataInfo<AttendanceAlertVo> queryPageList(AttendanceAlertBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<AttendanceAlert> lqw = buildQueryWrapper(bo);
        Page<AttendanceAlertVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);

        // 填充员工姓名和字典名称
        fillEmployeeInfoAndDictNames(result.getRecords());

        return TableDataInfo.build(result);
    }

    @Override
    public List<AttendanceAlertVo> queryList(AttendanceAlertBo bo) {
        LambdaQueryWrapper<AttendanceAlert> lqw = buildQueryWrapper(bo);
        List<AttendanceAlertVo> list = baseMapper.selectVoList(lqw);

        // 填充员工姓名和字典名称
        fillEmployeeInfoAndDictNames(list);

        return list;
    }

    private LambdaQueryWrapper<AttendanceAlert> buildQueryWrapper(AttendanceAlertBo bo) {
        LambdaQueryWrapper<AttendanceAlert> lqw = Wrappers.lambdaQuery();
        if (StringUtils.isNotBlank(bo.getEmployeeName())) {
            List<HrEmployee> employees = employeeMapper.selectList(
                Wrappers.lambdaQuery(HrEmployee.class)
                    .like(HrEmployee::getEmployeeName, bo.getEmployeeName()));
            List<String> employeeNos = Optional.ofNullable(employees)
                .orElse(Collections.emptyList())
                .stream()
                .map(HrEmployee::getEmployeeNo)
                .collect(Collectors.toList());

            if (CollUtil.isEmpty(employeeNos)) {
                lqw.eq(AttendanceAlert::getEmployeeNo, -1);
            } else {
                lqw.in(AttendanceAlert::getEmployeeNo, employeeNos);
            }
        }
        //lqw.eq(StringUtils.isNotBlank(bo.getEmployeeNo()), AttendanceAlert::getEmployeeNo, bo.getEmployeeNo());
        lqw.eq(bo.getUserId() != null, AttendanceAlert::getUserId, bo.getUserId());
        lqw.eq(StringUtils.isNotBlank(bo.getAlertType()), AttendanceAlert::getAlertType, bo.getAlertType());
        lqw.eq(StringUtils.isNotBlank(bo.getProcessStatus()), AttendanceAlert::getProcessStatus, bo.getProcessStatus());
        lqw.ge(bo.getAlertDate() != null, AttendanceAlert::getAlertDate, bo.getAlertDate());
        lqw.orderByDesc(AttendanceAlert::getCreateTime);
        return lqw;
    }

    private void fillEmployeeInfoAndDictNames(List<AttendanceAlertVo> list) {
        if (list.isEmpty()) {
            return;
        }

        // 收集工号
        List<String> employeeNos = list.stream()
                .map(AttendanceAlertVo::getEmployeeNo)
                .filter(StringUtils::isNotBlank)
                .distinct()
                .collect(Collectors.toList());

        if (employeeNos.isEmpty()) {
            return;
        }

        // 批量查询员工信息
        List<HrEmployee> employees = employeeMapper.selectList(
                Wrappers.lambdaQuery(HrEmployee.class)
                        .in(HrEmployee::getEmployeeNo, employeeNos));

        // 构建工号到员工的映射
        Map<String, HrEmployee> employeeMap = employees.stream()
                .collect(Collectors.toMap(HrEmployee::getEmployeeNo, e -> e));

        // 填充员工姓名和字典名称
        for (AttendanceAlertVo vo : list) {
            HrEmployee employee = employeeMap.get(vo.getEmployeeNo());
            if (employee != null) {
                vo.setEmployeeName(employee.getEmployeeName());
            }

            // 设置字典名称
            setDictNames(vo);
        }
    }

    private void setDictNames(AttendanceAlertVo vo) {
        // 设置提醒类型名称
        switch (vo.getAlertType()) {
            case "1":
                vo.setAlertTypeName("迟到");
                break;
            case "2":
                vo.setAlertTypeName("早退");
                break;
            case "3":
                vo.setAlertTypeName("旷工");
                break;
            case "4":
                vo.setAlertTypeName("未审批加班");
                break;
            default:
                vo.setAlertTypeName("未知");
                break;
        }

        // 设置关联记录类型名称
        switch (vo.getRelatedType()) {
            case "1":
                vo.setRelatedTypeName("考勤记录");
                break;
            case "2":
                vo.setRelatedTypeName("加班记录");
                break;
            default:
                vo.setRelatedTypeName("未知");
                break;
        }

        // 设置处理状态名称
        switch (vo.getProcessStatus()) {
            case "0":
                vo.setProcessStatusName("未处理");
                break;
            case "1":
                vo.setProcessStatusName("已处理");
                break;
            default:
                vo.setProcessStatusName("未知");
                break;
        }
    }

    @Override
    public AttendanceAlertVo queryById(Long alertId) {
        AttendanceAlertVo vo = baseMapper.selectVoById(alertId);
        if (vo != null) {
            // 填充员工姓名和字典名称
            if (StringUtils.isNotBlank(vo.getEmployeeNo())) {
                HrEmployee employee = employeeMapper.selectOne(
                        Wrappers.lambdaQuery(HrEmployee.class)
                                .eq(HrEmployee::getEmployeeNo, vo.getEmployeeNo())
                                .last("LIMIT 1"));
                if (employee != null) {
                    vo.setEmployeeName(employee.getEmployeeName());
                }
            }
            setDictNames(vo);
        }
        return vo;
    }

    @Override
    public Boolean insertByBo(AttendanceAlertBo bo) {
        AttendanceAlert add = MapstructUtils.convert(bo, AttendanceAlert.class);
        if(null != bo.getAlertId()){
           return this.updateByBo(bo);
        }
        return baseMapper.insert(add) > 0;
    }

    @Override
    public Boolean updateByBo(AttendanceAlertBo bo) {
        AttendanceAlert update = MapstructUtils.convert(bo, AttendanceAlert.class);
        return baseMapper.updateById(update) > 0;
    }

    @Override
    public Boolean deleteWithValidById(Long alertId) {
        return baseMapper.deleteById(alertId) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void generateAlerts(LocalDate alertDate) {
        log.info("开始生成{}的考勤异常提醒", alertDate);

        // 生成迟到、早退、旷工提醒
        generateAttendanceAlerts(alertDate);

        // 生成未审批加班提醒
        generateOvertimeAlerts(alertDate);

        log.info("{}的考勤异常提醒生成完成", alertDate);
    }

    /**
     * 生成考勤异常提醒(迟到、早退、旷工)
     */
    private void generateAttendanceAlerts(LocalDate alertDate) {
        // 查询指定日期的异常考勤记录
        List<AttendanceRecord> abnormalRecords = attendanceRecordMapper.selectList(
                Wrappers.lambdaQuery(AttendanceRecord.class)
                        .eq(AttendanceRecord::getAttendanceDate, alertDate)
                        .in(AttendanceRecord::getAttendanceStatus, "1", "2", "3")); // 迟到、早退、旷工

        for (AttendanceRecord record : abnormalRecords) {
            // 检查是否已存在相同类型的提醒
            Long count = baseMapper.selectCount(
                    Wrappers.lambdaQuery(AttendanceAlert.class)
                            .eq(AttendanceAlert::getEmployeeNo, record.getEmployeeNo())
                            .eq(AttendanceAlert::getAlertType, record.getAttendanceStatus())
                            .eq(AttendanceAlert::getRelatedId, record.getRecordId())
                            .eq(AttendanceAlert::getRelatedType, "1"));

            if (count != null && count > 0) {
                continue; // 已存在提醒，跳过
            }

            // 创建提醒
            AttendanceAlert alert = new AttendanceAlert();
            alert.setEmployeeNo(record.getEmployeeNo());
            alert.setUserId(record.getUserId());
            alert.setAlertType(record.getAttendanceStatus()); // 1迟到 2早退 3旷工
            alert.setRelatedId(record.getRecordId());
            alert.setRelatedType("1"); // 考勤记录
            alert.setAlertDate(alertDate);
            alert.setAlertContent(buildAttendanceAlertContent(record));
            alert.setProcessStatus("0"); // 未处理

            baseMapper.insert(alert);
        }
    }

    /**
     * 生成未审批加班提醒
     */
    private void generateOvertimeAlerts(LocalDate alertDate) {
        // 查询指定日期的未审批加班记录
        List<OvertimeRecord> unapprovedRecords = overtimeRecordMapper.selectList(
                Wrappers.lambdaQuery(OvertimeRecord.class)
                        .eq(OvertimeRecord::getOvertimeDate, alertDate)
                        .eq(OvertimeRecord::getApprovalStatus, "0")); // 待审批

        for (OvertimeRecord record : unapprovedRecords) {
            // 检查是否已存在相同类型的提醒
            Long count = baseMapper.selectCount(
                    Wrappers.lambdaQuery(AttendanceAlert.class)
                            .eq(AttendanceAlert::getEmployeeNo, record.getEmployeeNo())
                            .eq(AttendanceAlert::getAlertType, "4") // 未审批加班
                            .eq(AttendanceAlert::getRelatedId, record.getRecordId())
                            .eq(AttendanceAlert::getRelatedType, "2"));

            if (count != null && count > 0) {
                continue; // 已存在提醒，跳过
            }

            // 创建提醒
            AttendanceAlert alert = new AttendanceAlert();
            alert.setEmployeeNo(record.getEmployeeNo());
            alert.setUserId(record.getUserId());
            alert.setAlertType("4"); // 未审批加班
            alert.setRelatedId(record.getRecordId());
            alert.setRelatedType("2"); // 加班记录
            alert.setAlertDate(alertDate);
            alert.setAlertContent(buildOvertimeAlertContent(record));
            alert.setProcessStatus("0"); // 未处理

            baseMapper.insert(alert);
        }
    }

    /**
     * 构建考勤异常提醒内容
     */
    private String buildAttendanceAlertContent(AttendanceRecord record) {
        StringBuilder content = new StringBuilder();
        content.append("员工在").append(record.getAttendanceDate()).append("出现");

        switch (record.getAttendanceStatus()) {
            case "1":
                content.append("迟到");
                break;
            case "2":
                content.append("早退");
                break;
            case "3":
                content.append("旷工");
                break;
            default:
                content.append("异常考勤");
                break;
        }

        content.append("，打卡时间：").append(record.getClockTime());
        if (StringUtils.isNotBlank(record.getExceptionReason())) {
            content.append("，原因：").append(record.getExceptionReason());
        }

        return content.toString();
    }

    /**
     * 构建加班异常提醒内容
     */
    private String buildOvertimeAlertContent(OvertimeRecord record) {
        return String.format("员工在%s申请加班，时长%d分钟，尚未审批",
                record.getOvertimeDate(), record.getOvertimeMinutes());
    }

    @Override
    public void sendMonthlyAlertSummary(Integer year, Integer month) {
        log.info("开始发送{}年{}月的考勤异常汇总邮件", year, month);

        // 这里应该实现发送邮件的逻辑
        // 由于邮件发送功能可能需要额外的配置和依赖，这里只做日志记录
        log.info("月度考勤异常汇总邮件发送功能待实现");

        // 实际实现应该：
        // 1. 查询指定月份的异常考勤统计
        // 2. 获取各部门负责人信息
        // 3. 生成汇总报表
        // 4. 发送邮件给各部门负责人
    }
}
